package cn.trigram.file;

import cn.trigram.asserts.AssertUtil;
import cn.trigram.exception.FileOperationException;
import cn.trigram.exception.GeneralException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;

/**
 * 路径处理工具
 *
 * @author 一日看尽长安花
 */
public class PathUtil {

  /**
   * jar启动时classes路径中识别的特殊目录
   */
  public static final String JAR_SPECIFIC = "BOOT-INF";

  /**
   * war启动时classes路径中识别的特殊目录
   */
  public static final String WAR_SPECIFIC = "WEB-INF";

  public static Pattern FILE_SEPARATOR_PATTER = Pattern.compile("\\/");

  /**
   * 获取部署根目录 <br/> e.g: <br/> tomcat部署路径： <br/> file:/D:/develop_program/apache-tomcat-8.5.68/webapps/mvctest/WEB-INF/classes/
   * <br/> springboot运行路径： <br/> jar:file:/E:/code_workspace/idea/BenefitCode/benefit-springboot/target/benefit-springboot-0.0.1-exec.jar!/BOOT-INF/classes!/
   * <br/> 通过{@code Paths.get(".")}路径是以java执行程序的目录为准，所以不能用 <br/> 注：建议缓存结果
   */
  public static Path getDeployPath() {

    URL      classesPathUrl = Thread.currentThread().getContextClassLoader().getResource("");
    String   protocol       = classesPathUrl.getProtocol();
    String   externalForm   = classesPathUrl.toExternalForm();
    String[] pathSeps       = FILE_SEPARATOR_PATTER.split(externalForm);
    int      endIdx         = pathSeps.length;
    if (StringUtils.equals(protocol, "jar")) {
      if (StringUtils.contains(externalForm, JAR_SPECIFIC)) {
        /*springboot jar 方式启动，取jar文件所在目录*/
        for (int i = 1; i < endIdx; i++) {
          if (StringUtils.equals(JAR_SPECIFIC, pathSeps[i])) {
            endIdx = i - 1;
            break;
          }
        }
      } else {
        throw new GeneralException("未知的启动classpath路径");
      }
    } else {
      if (StringUtils.contains(externalForm, WAR_SPECIFIC)) {
        /*war 方式启动, 取WEB-INF文件夹所在的目录，一般以项目名命名的那个目录*/
        for (int i = 1; i < endIdx; i++) {
          if (StringUtils.equals(WAR_SPECIFIC, pathSeps[i])) {
            endIdx = i;
            break;
          }
        }
      } else {
        /*开发时的目录,maven模式下一般是target目录*/
        endIdx = pathSeps.length - 1;
      }
    }
    pathSeps[0] = "file:";

    try {
      return Paths.get(new URI(StringUtils.join(pathSeps, "/", 0, endIdx)));
    } catch (URISyntaxException e) {
      throw new GeneralException("获取项目部署根目录失败", e);
    }
  }

  public static Path resolve(Path basePath, String other) {

    AssertUtil.assertNotNull(basePath, "基目录为NULL");
    /*
    resolve并不会立刻进行解析，需要调用normalize进行解析
    注：normalize 只是一个纯粹的句法操作
    */
    return basePath.resolve(other).normalize();
  }

  public static boolean isExists(Path path) {

    if (!Files.exists(path) && !Files.notExists(path)) {
//   如果同时 exists 和 notExists 回报 false，该文件的存在，无法验证。
      throw new FileOperationException(String.format("文件[%s]的存在无法验证", path.toAbsolutePath()));
    }
//    注意 !Files.exists(path) 不等同于 Files.notExists(path)
    return Files.exists(path);
  }

  public static boolean isAccess(Path path) {

    return Files.isRegularFile(path) &
           Files.isReadable(path);
  }

  public static PathMatcher getPathMatcher(String syntaxAndPattern) {

    return FileSystems.getDefault().getPathMatcher(syntaxAndPattern);
  }

}
